const express = require('express');
const puppeteer = require('puppeteer');
const fs = require('fs');
const path = require('path');
const winston = require('winston');
const cors = require('cors');
const multer = require('multer');

// 获取北京时间的工具函数
const getBeijingTime = () => {
    const now = new Date();
    const beijingTime = new Date(now.getTime() + (8 * 60 * 60 * 1000));
    return beijingTime;
};

// 格式化北京时间为字符串
const formatBeijingTime = (date = null) => {
    const time = date || getBeijingTime();
    return time.toISOString().replace('T', ' ').replace('Z', ' +08:00');
};

// 创建日志记录器
const createLogger = () => {
    // 获取北京时间的日期字符串
    const beijingTime = getBeijingTime();
    const dateStr = beijingTime.toISOString().split('T')[0]; // YYYY-MM-DD
    const logDir = path.join(__dirname, 'logs');

    // 确保日志目录存在
    if (!fs.existsSync(logDir)) {
        fs.mkdirSync(logDir, { recursive: true });
    }

    return winston.createLogger({
        level: 'info',
        format: winston.format.combine(
            winston.format.timestamp(),
            winston.format.printf(({ timestamp, level, message }) => {
                // 将UTC时间转换为北京时间
                const utcTime = new Date(timestamp);
                const beijingTime = new Date(utcTime.getTime() + (8 * 60 * 60 * 1000));
                const beijingTimeStr = beijingTime.toISOString().replace('T', ' ').replace('Z', ' +08:00');
                return `${beijingTimeStr} [${level.toUpperCase()}] ${message}`;
            })
        ),
        transports: [
            new winston.transports.File({
                filename: path.join(logDir, `screenshot-service-${dateStr}.log`)
            }),
            new winston.transports.Console()
        ]
    });
};

const logger = createLogger();

// 全局浏览器实例
let globalBrowser = null;
let isInitializing = false;
let server = null;

/**
 * 初始化浏览器实例
 */
async function initBrowser() {
    if (globalBrowser && globalBrowser.isConnected()) {
        logger.info('浏览器实例已存在，无需重新初始化');
        return globalBrowser;
    }

    if (isInitializing) {
        logger.info('浏览器正在初始化中，等待完成...');
        while (isInitializing) {
            await new Promise(resolve => setTimeout(resolve, 100));
        }
        return globalBrowser;
    }

    logger.info('开始初始化浏览器实例...');
    isInitializing = true;
    
    const startTime = Date.now();

    try {
        globalBrowser = await puppeteer.launch({
            headless: "new",
            args: [
                '--no-sandbox',
                '--disable-setuid-sandbox',
                '--disable-dev-shm-usage',
                '--disable-web-security',
                '--no-first-run',
                '--disable-background-timer-throttling',
                '--disable-backgrounding-occluded-windows',
                '--disable-renderer-backgrounding',
                '--disable-features=TranslateUI',
                '--disable-extensions',
                '--disable-default-apps'
            ]
        });

        const endTime = Date.now();
        logger.info(`浏览器初始化成功，耗时: ${endTime - startTime}ms`);

        globalBrowser.on('disconnected', () => {
            logger.warn('浏览器实例已断开连接');
            globalBrowser = null;
        });

        return globalBrowser;

    } catch (error) {
        logger.error(`浏览器初始化失败: ${error.message}`);
        globalBrowser = null;
        throw error;
    } finally {
        isInitializing = false;
    }
}

/**
 * 获取浏览器实例
 */
async function getBrowser() {
    if (!globalBrowser || !globalBrowser.isConnected()) {
        return await initBrowser();
    }
    return globalBrowser;
}

/**
 * 执行截图 - 支持HTML文件路径和HTML内容
 */
async function screenshot(htmlFilePath, outputImagePath, options = {}) {
    logger.info(`开始截图任务: ${htmlFilePath} -> ${outputImagePath}`);

    const taskStartTime = Date.now();

    const config = {
        width: 1200,
        height: 800,
        deviceScaleFactor: 2,
        fullPage: true,
        quality: 90,
        type: 'png',
        autoSize: false,
        ...options
    };

    try {
        const browserStartTime = Date.now();
        const browser = await getBrowser();
        const browserEndTime = Date.now();

        const browserTime = browserEndTime - browserStartTime;
        logger.info(`浏览器获取耗时: ${browserTime}ms`);

        const page = await browser.newPage();

        try {
            await page.setViewport({
                width: config.width,
                height: config.height,
                deviceScaleFactor: config.deviceScaleFactor
            });

            // 检查HTML文件是否存在
            if (!fs.existsSync(htmlFilePath)) {
                throw new Error(`HTML文件不存在: ${htmlFilePath}`);
            }

            // 读取HTML文件内容
            const htmlContent = fs.readFileSync(htmlFilePath, 'utf-8');
            logger.info(`读取HTML文件成功，内容长度: ${htmlContent.length}`);

            await page.setContent(htmlContent, {
                waitUntil: 'networkidle0',
                timeout: 15000
            });

            if (config.autoSize) {
                const contentSize = await page.evaluate(() => {
                    const body = document.body;
                    const html = document.documentElement;
                    return {
                        width: Math.max(body.scrollWidth, body.offsetWidth, html.clientWidth, html.scrollWidth, html.offsetWidth),
                        height: Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight)
                    };
                });
                
                const finalWidth = Math.max(config.width, contentSize.width);
                const finalHeight = Math.max(config.height, contentSize.height);
                
                if (finalWidth !== config.width || finalHeight !== config.height) {
                    await page.setViewport({
                        width: finalWidth,
                        height: finalHeight,
                        deviceScaleFactor: config.deviceScaleFactor
                    });
                }
            }

            await page.evaluate(() => document.fonts.ready);
            await page.waitForTimeout(300);

            const screenshotOptions = {
                path: outputImagePath,
                fullPage: config.fullPage,
                type: config.type
            };

            if (config.type === 'jpeg') {
                screenshotOptions.quality = config.quality;
            }

            await page.screenshot(screenshotOptions);

            const taskEndTime = Date.now();
            logger.info(`截图完成，总耗时: ${taskEndTime - taskStartTime}ms`);

            return {
                success: true,
                time: taskEndTime - taskStartTime
            };

        } finally {
            await page.close();
        }
        
    } catch (error) {
        const taskEndTime = Date.now();
        logger.error(`截图失败，总耗时: ${taskEndTime - taskStartTime}ms, 错误: ${error.message}`);
        throw error;
    }
}

/**
 * 执行截图 - 从HTML内容生成图片并返回buffer (用于前端下载)
 */
async function screenshotFromContent(htmlContent, options = {}) {
    logger.info(`开始截图任务，HTML内容长度: ${htmlContent.length}`);

    const taskStartTime = Date.now();

    const config = {
        width: 1200,
        height: 800,
        deviceScaleFactor: 2,
        fullPage: true,
        quality: 90,
        type: 'png',
        autoSize: false,
        ...options
    };

    try {
        const browserStartTime = Date.now();
        const browser = await getBrowser();
        const browserEndTime = Date.now();

        const browserTime = browserEndTime - browserStartTime;
        logger.info(`浏览器获取耗时: ${browserTime}ms`);

        const page = await browser.newPage();

        try {
            await page.setViewport({
                width: config.width,
                height: config.height,
                deviceScaleFactor: config.deviceScaleFactor
            });

            await page.setContent(htmlContent, {
                waitUntil: 'networkidle0',
                timeout: 15000
            });

            if (config.autoSize) {
                const contentSize = await page.evaluate(() => {
                    const body = document.body;
                    const html = document.documentElement;
                    return {
                        width: Math.max(body.scrollWidth, body.offsetWidth, html.clientWidth, html.scrollWidth, html.offsetWidth),
                        height: Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight)
                    };
                });

                const finalWidth = Math.max(config.width, contentSize.width);
                const finalHeight = Math.max(config.height, contentSize.height);

                if (finalWidth !== config.width || finalHeight !== config.height) {
                    await page.setViewport({
                        width: finalWidth,
                        height: finalHeight,
                        deviceScaleFactor: config.deviceScaleFactor
                    });
                }
            }

            await page.evaluate(() => document.fonts.ready);
            await page.waitForTimeout(300);

            const screenshotOptions = {
                fullPage: config.fullPage,
                type: config.type
            };

            if (config.type === 'jpeg') {
                screenshotOptions.quality = config.quality;
            }

            const screenshotBuffer = await page.screenshot(screenshotOptions);

            const taskEndTime = Date.now();
            logger.info(`截图完成，总耗时: ${taskEndTime - taskStartTime}ms`);

            return {
                success: true,
                time: taskEndTime - taskStartTime,
                buffer: screenshotBuffer,
                type: config.type
            };

        } finally {
            await page.close();
        }

    } catch (error) {
        const taskEndTime = Date.now();
        logger.error(`截图失败，总耗时: ${taskEndTime - taskStartTime}ms, 错误: ${error.message}`);
        throw error;
    }
}

/**
 * 关闭浏览器实例
 */
async function closeBrowser() {
    if (globalBrowser) {
        logger.info('正在关闭浏览器实例...');
        try {
            await globalBrowser.close();
            logger.info('浏览器实例已关闭');
        } catch (error) {
            logger.error(`关闭浏览器时出错: ${error.message}`);
        }
        globalBrowser = null;
    }
}

// 创建Express应用
const app = express();

// 启用CORS，允许前端页面访问
app.use(cors());
app.use(express.json({ limit: '10mb' }));
app.use(express.text({ limit: '10mb' }));

// 配置multer用于处理文件上传
const upload = multer();

// 健康检查接口
app.get('/health', (req, res) => {
    const status = {
        status: 'ok',
        timestamp: formatBeijingTime(),
        browser: {
            initialized: globalBrowser !== null,
            connected: globalBrowser && globalBrowser.isConnected(),
            initializing: isInitializing
        }
    };
    res.json(status);
});

// 初始化浏览器接口
app.post('/init', async (req, res) => {
    try {
        logger.info('收到初始化浏览器请求');
        await initBrowser();
        res.json({ success: true, message: '浏览器初始化成功' });
    } catch (error) {
        logger.error(`初始化浏览器失败: ${error.message}`);
        res.status(500).json({ success: false, error: error.message });
    }
});

// 截图接口 - 支持文件路径和HTML内容两种方式
app.post('/screenshot', async (req, res) => {
    try {
        const { htmlFilePath, outputImagePath, htmlContent, options = {} } = req.body;

        // 方式1: 使用文件路径 (Java后端调用)
        if (htmlFilePath && outputImagePath) {
            logger.info(`收到文件路径截图请求: ${htmlFilePath} -> ${outputImagePath}`);

            const result = await screenshot(htmlFilePath, outputImagePath, options);
            res.json(result);
            return;
        }

        // 方式2: 使用HTML内容 (前端页面调用)
        if (htmlContent) {
            logger.info(`收到HTML内容截图请求，内容长度: ${htmlContent.length}`);

            const result = await screenshotFromContent(htmlContent, options);

            // 设置响应头
            const filename = `screenshot-${Date.now()}.${result.type}`;
            res.setHeader('Content-Type', `image/${result.type}`);
            res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
            res.setHeader('Content-Length', result.buffer.length);

            // 返回图片数据
            res.send(result.buffer);
            return;
        }

        // 参数错误
        return res.status(400).json({
            success: false,
            error: '请提供 htmlFilePath+outputImagePath 或 htmlContent 参数'
        });

    } catch (error) {
        logger.error(`截图请求处理失败: ${error.message}`);
        res.status(500).json({ success: false, error: error.message });
    }
});

// 关闭服务接口
app.post('/shutdown', async (req, res) => {
    try {
        logger.info('收到关闭服务请求');
        res.json({ success: true, message: '服务正在关闭...' });
        
        // 延迟关闭，确保响应发送完成
        setTimeout(async () => {
            await closeBrowser();
            if (server) {
                server.close(() => {
                    logger.info('HTTP服务已关闭');
                    process.exit(0);
                });
            }
        }, 1000);
        
    } catch (error) {
        logger.error(`关闭服务失败: ${error.message}`);
        res.status(500).json({ success: false, error: error.message });
    }
});

// 启动服务器
const PORT = process.env.PORT || 3000;

async function startServer() {
    try {
        // 预先初始化浏览器
        logger.info('服务启动中，预先初始化浏览器...');
        await initBrowser();
        
        server = app.listen(PORT, () => {
            logger.info(`截图HTTP服务已启动，端口: ${PORT}`);
            logger.info(`健康检查: http://localhost:${PORT}/health`);
        });
        
    } catch (error) {
        logger.error(`服务启动失败: ${error.message}`);
        process.exit(1);
    }
}

// 进程退出处理
process.on('SIGINT', async () => {
    logger.info('接收到中断信号，正在清理资源...');
    await closeBrowser();
    if (server) {
        server.close(() => {
            logger.info('服务已关闭');
            process.exit(0);
        });
    }
});

process.on('SIGTERM', async () => {
    logger.info('接收到终止信号，正在清理资源...');
    await closeBrowser();
    if (server) {
        server.close(() => {
            logger.info('服务已关闭');
            process.exit(0);
        });
    }
});

process.on('uncaughtException', async (error) => {
    logger.error(`未捕获的异常: ${error.message}`);
    await closeBrowser();
    process.exit(1);
});

// 启动服务
if (require.main === module) {
    startServer();
}

module.exports = { app, startServer, closeBrowser };
